/*
自定义高阶函数组件，实现组件或插槽内容的加载状态，错误，及结果的自动显示，用法如下：

1、数据获取请求定义：
_request为返回的Promise对象
const _request = (params) => {
    return api.get(`api/v3/trade/market`, {showError:false, showLoading:false})
}

2、组装高阶函数,只有1个参数时，传数据请求函数，2个参数时，位置1为定义的vue组件

let hoc = new Hoc(_request)
或
let hoc = new Hoc(About, _request)

3、将组装的高阶函数定义为组件

components: {
    hoc,
}

4、组件传参：fixed 为加载状态及错误结果是否全屏显示

4.1、无组件参数时，暴露默认数据插槽  #default="{data}" 获取数据
<hoc :params="params" #default="{data}" fixed>...</hoc>
@:params 为默认插槽时，为请求函数_request传参，展示的内容为声明的高阶函数组件内部插槽内容

4.2、有组件传参时，例如组件为About,展示的内容为组件内容，需在About内用如下形式传参和接收数据,组件内有插槽时，可在hoc内设置插槽内容
<hoc fixed>...</hoc>
About组件内部：
export default {
  props: ['data'],
  setup(){
    const params = ref('zh-CN')
    return {
      params
    }
  },
}
*/


import FLoading from '@/components/FLoading'
import ErrorMC from './hoc_error'
import ViewState from './view_state.js'
import {SUCCESS} from '@/api'
import { getCurrentInstance, onMounted, ref, watch, h } from 'vue'
import { useI18n } from 'vue-i18n'

export default function(WrappedComponent, promiseFn) {
  if(!promiseFn){
    promiseFn = WrappedComponent
    WrappedComponent = null
  }
  return {
    props: {
      params: {
        default: null
      },
      fixed: {
        type: Boolean,
        default: false
      }
    },
    setup(props, ctx){
      const self = getCurrentInstance()
      const {t} = useI18n()
      const viewState = ref(ViewState.busy)
      const message = ref('')
      const data = ref(null)
      const reqParams = ref(null)

      async function request() {
        viewState.value = ViewState.busy
        const result = await promiseFn(reqParams.value)
        if (result.rst != SUCCESS) {
          message.value = `${result.code||''} ${t('error_code.'+result.msg).replace('error_code.','')}`
          if (result.path) {
            message.value = `path: ${result.path}<br/>${message.value}`
          }
          viewState.value = ViewState.error
        } else {
          data.value = result.data
          viewState.value = ViewState.idle
        }
      }

      onMounted(()=>{
        // 立刻发送请求，并且监听参数变化重新请求
        reqParams.value = WrappedComponent && self.refs.wrapped.params || props.params
        watch(reqParams, ()=>request(), {
          immediate: true,
          deep:true
        })
      })

      return {
        viewState,
        message,
        data,
        request
      }
    },
    render() {
      const slots = {...this.$slots}
      slots.default = ()=> this.$slots.default({data:this.data})
      const args = {
        ref: 'wrapped',
        data: this.data,
        ...this.$attrs,
      }

      const wrapped = WrappedComponent || "div"
      const wrapper = h('div', {
        style: this.viewState != ViewState.idle?'position:relative; min-height: 2.1rem;':''
      }, [
        this.viewState == ViewState.busy ? h(FLoading, {
          color: '#c9c9c9',
          size: 30,
          fixed: this.fixed,
          bgColor: 'rgba(0, 0, 0, 0)',
        }) : (this.viewState == ViewState.error ? h(ErrorMC, {
          message: this.message,
          fixed: this.fixed,
          onRetry:()=> this.request()
        }) : null),
        this.viewState != ViewState.idle?
        h('div', {style:'visibility: hidden;'}, h(wrapped, args, null)):
        h(wrapped, args, slots),
      ])
      return wrapper
    },
  }
}